package com.centling.smartSealForPhone.receiver;

import android.content.Context;
import android.util.SparseArray;

import com.centling.smartSealForPhone.application.SmartSeal;
import com.centling.smartSealForPhone.constants.SPConstants;
import com.centling.smartSealForPhone.utils.LogUtil;
import com.centling.smartSealForPhone.utils.SPUtil;

import java.util.Locale;
import java.util.Set;

import cn.jpush.android.api.JPushInterface;
import cn.jpush.android.api.JPushMessage;

/**
 * @author fionera
 */
public class TagAliasOperatorHelper {
    public static int sequence = 1;

    private static final int ACTION_ADD = 1;
    private static final int ACTION_SET = 2;
    private static final int ACTION_DELETE = 3;
    private static final int ACTION_CLEAN = 4;
    private static final int ACTION_GET = 5;

    private static final int ACTION_CHECK = 6;

    private static TagAliasOperatorHelper mInstance;

    public static TagAliasOperatorHelper getInstance() {
        if (mInstance == null) {
            synchronized (TagAliasOperatorHelper.class) {
                if (mInstance == null) {
                    mInstance = new TagAliasOperatorHelper();
                }
            }
        }
        return mInstance;
    }

    private SparseArray<TagAliasBean> tagAliasActionCache = new SparseArray<>();

    public void put(int sequence, TagAliasBean tagAliasBean) {
        tagAliasActionCache.put(sequence, tagAliasBean);
    }

    public TagAliasBean get(int sequence) {
        return tagAliasActionCache.get(sequence);
    }

    public TagAliasBean remove(int sequence) {
        return tagAliasActionCache.get(sequence);
    }

    public void onTagOperatorResult(JPushMessage jPushMessage) {
        int sequence = jPushMessage.getSequence();
        TagAliasBean tagAliasBean = tagAliasActionCache.get(sequence);
        if (tagAliasBean == null) {
            return;
        }
        if (jPushMessage.getErrorCode() == 0) {
            tagAliasActionCache.remove(sequence);
            LogUtil.d(getActionStr(tagAliasBean.action) + " tags success");
        } else {
            String logs = "Failed to " + getActionStr(tagAliasBean.action) + " tags";
            if (jPushMessage.getErrorCode() == 6018) {
                // tag数量超过限制, 需要先清除一部分再add
                logs += ", tags is exceed limit need to clean";
            }
            logs += ", errorCode:" + jPushMessage.getErrorCode();
            LogUtil.d(logs);
            retryActionIfNeeded(jPushMessage.getErrorCode(), tagAliasBean);
        }
    }

    public void onCheckTagOperatorResult(JPushMessage jPushMessage) {
        int sequence = jPushMessage.getSequence();
        TagAliasBean tagAliasBean = tagAliasActionCache.get(sequence);
        if (tagAliasBean == null) {
            return;
        }
        if (jPushMessage.getErrorCode() == 0) {
            tagAliasActionCache.remove(sequence);
            LogUtil.d(getActionStr(tagAliasBean.action) + " tag " + jPushMessage
                    .getCheckTag() + " bind state success,state:" + jPushMessage
                    .getTagCheckStateResult());
        } else {
            LogUtil.d("Failed to " + getActionStr(
                    tagAliasBean.action) + " tags, errorCode:" + jPushMessage.getErrorCode());
            retryActionIfNeeded(jPushMessage.getErrorCode(), tagAliasBean);
        }
    }

    public void onAliasOperatorResult(JPushMessage jPushMessage) {
        int sequence = jPushMessage.getSequence();
        TagAliasBean tagAliasBean = tagAliasActionCache.get(sequence);
        if (tagAliasBean == null) {
            return;
        }
        if (jPushMessage.getErrorCode() == 0) {
            tagAliasActionCache.remove(sequence);
            LogUtil.d(getActionStr(tagAliasBean.action) + " alias success");
            SPUtil.setBoolean(SPConstants.IS_SET_ALIAS, true);
        } else {
            LogUtil.d("Failed to " + getActionStr(
                    tagAliasBean.action) + " alias, errorCode:" + jPushMessage.getErrorCode());
            retryActionIfNeeded(jPushMessage.getErrorCode(), tagAliasBean);
        }
    }

    private String getActionStr(int actionType) {
        switch (actionType) {
            case ACTION_ADD:
                return "add";
            case ACTION_SET:
                return "set";
            case ACTION_DELETE:
                return "delete";
            case ACTION_GET:
                return "get";
            case ACTION_CLEAN:
                return "clean";
            case ACTION_CHECK:
                return "check";
            default:
                return "unknown operation";
        }
    }

    private void retryActionIfNeeded(int errorCode, TagAliasBean tagAliasBean) {
        // 返回的错误码为6002 超时,6014 服务器繁忙, 都建议延迟重试
        if (errorCode == 6002 || errorCode == 6014) {
            if (tagAliasBean != null) {
                sequence++;
                tagAliasActionCache.put(sequence, tagAliasBean);
                handleAction(sequence, tagAliasBean);
                LogUtil.d(getRetryStr(tagAliasBean.isAliasAction, tagAliasBean.action, errorCode));
            }
        }
    }

    /**
     * 处理设置tag
     */
    private void handleAction(int sequence, TagAliasBean tagAliasBean) {
        Context context = SmartSeal.getInstance();
        if (tagAliasBean == null) {
            return;
        }
        put(sequence, tagAliasBean);
        if (tagAliasBean.isAliasAction) {
            switch (tagAliasBean.action) {
                case ACTION_GET:
                    JPushInterface.getAlias(context, sequence);
                    break;
                case ACTION_DELETE:
                    JPushInterface.deleteAlias(context, sequence);
                    break;
                case ACTION_SET:
                    JPushInterface.setAlias(context, sequence, tagAliasBean.alias);
                    break;
                default:
                    break;
            }
        } else {
            switch (tagAliasBean.action) {
                case ACTION_ADD:
                    JPushInterface.addTags(context, sequence, tagAliasBean.tags);
                    break;
                case ACTION_SET:
                    JPushInterface.setTags(context, sequence, tagAliasBean.tags);
                    break;
                case ACTION_DELETE:
                    JPushInterface.deleteTags(context, sequence, tagAliasBean.tags);
                    break;
                case ACTION_CHECK:
                    String tag = (String) tagAliasBean.tags.toArray()[0];
                    JPushInterface.checkTagBindState(context, sequence, tag);
                    break;
                case ACTION_GET:
                    JPushInterface.getAllTags(context, sequence);
                    break;
                case ACTION_CLEAN:
                    JPushInterface.cleanTags(context, sequence);
                    break;
                default:
                    break;
            }
        }
    }

    private String getRetryStr(boolean isAliasAction, int actionType, int errorCode) {
        String str = "Failed to %s %s due to %s. Try again after 60s.";
        str = String.format(Locale.CHINA, str, getActionStr(actionType),
                (isAliasAction ? "alias" : " tags"),
                (errorCode == 6002 ? "timeout" : "server too busy"));
        return str;
    }

    public static class TagAliasBean {
        int action;
        Set<String> tags;
        String alias;
        boolean isAliasAction;

        @Override
        public String toString() {
            return "TagAliasBean{" + "action=" + action + ", tags=" + tags + ", alias='" + alias
                    + '\'' + ", isAliasAction=" + isAliasAction + '}';
        }
    }
}
